package com.gcb.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gcb.common.enums.AuthStatusEnum;
import com.gcb.common.enums.CreateTypeEnum;
import com.gcb.common.enums.ShipState;
import com.gcb.common.enums.ShipTypeEnum;
import com.gcb.common.exception.ServiceException;
import com.gcb.common.utils.DateUtils;
import com.gcb.common.utils.DistanceCalculatorUtils;
import com.gcb.common.utils.ShipAPIUtil;
import com.gcb.common.utils.StringUtils;
import com.gcb.domain.bo.ShipBIBO;
import com.gcb.domain.dto.ShipAppQueryPageDTO;
import com.gcb.domain.dto.ShipQueryDTO;
import com.gcb.domain.dto.ShipSaveDTO;
import com.gcb.domain.entity.Company;
import com.gcb.domain.entity.Ship;
import com.gcb.domain.entity.ShipTrajectory;
import com.gcb.domain.vo.ShipTrajectoryVO;
import com.gcb.domain.vo.ShipVO;
import com.gcb.mapper.CompanyMapper;
import com.gcb.mapper.ShipMapper;
import com.gcb.service.IShipService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ShipServiceImpl extends ServiceImpl<ShipMapper , Ship> implements IShipService {

    @Resource
    private ShipMapper mapper;

    @Resource
    private CompanyMapper companyMapper;

    @Override
    public List<Ship> getAllList() {
        return mapper.selectList(null)
                .stream()
                .filter(x -> StrUtil.isNotBlank(x.getMmsiCode()))
                .collect(Collectors.toList());
    }

    @Override
    public List<ShipVO> pageList(ShipQueryDTO dto) {
        List<ShipVO> pageList = mapper.pageList(dto);
        pageList.forEach(ShipServiceImpl::handleVO);
        return pageList;
    }

    private static void handleVO(ShipVO x) {
        x.setShipTypeStr(ShipTypeEnum.getInfo(x.getShipType()));
        x.setAuthStatusStr(AuthStatusEnum.getInfo(x.getAuthStatus()));
        x.setCreateTypeStr(CreateTypeEnum.getInfo(x.getCreateType()));
    }

    @Override
    public void save(ShipSaveDTO dto, Long currentUserId) {
        Ship ship = BeanUtil.copyProperties(dto, Ship.class);
        if (StrUtil.isNotBlank(dto.getShipPic())) {
            ship.setShipPic(JSONUtil.parseArray(dto.getShipPic()).toString());
        }
        Company company = companyMapper.selectCompanyById(dto.getCompanyId());

        String existName = mapper.existNameByCompanyId(dto.getShipName(), company.getId(), null);
        if (StrUtil.isNotBlank(existName)) {
            throw new ServiceException("同一个企业下船舶名称不能重复");
        }

        JSONObject shipInfoJSON = ShipAPIUtil.getShipMMSIByName(dto.getShipName());
        if (!JSONUtil.isNull(shipInfoJSON)) {
            JSONObject data = shipInfoJSON.getJSONArray("data").getJSONObject(0);
            ship.setMmsiCode(data.getStr("mmsi"));
            ship.setShipId(data.getStr("ShipID"));
            //说明用户选择其他类型 需要从船讯网获取船只类型
            if (dto.getShipType().equals("99")) {
                ship.setShipType(data.getInt("shiptype"));
            }
        }

        //4.1版本添加默认为已认证
        ship.setAuthStatus(3);
        ship.setOperatorId(company.getOperateId());
        ship.setCreateBy(currentUserId);
        ship.setCreateTime(new Date());
        ship.setUpdateBy(currentUserId);
        ship.setUpdateTime(new Date());
        mapper.insert(ship);
    }

    @Override
    public void update(ShipSaveDTO dto, Long currentUserId) {
        Ship ship = BeanUtil.copyProperties(dto, Ship.class);
        if (StrUtil.isNotBlank(dto.getShipPic())) {
            ship.setShipPic(JSONUtil.parseArray(dto.getShipPic()).toString());
        }
        Company company = companyMapper.selectCompanyById(dto.getCompanyId());
        String existName = mapper.existNameByCompanyId(dto.getShipName(), company.getId(), dto.getId());
        if (StrUtil.isNotBlank(existName)) {
            throw new ServiceException("同一个企业下船舶名称不能重复");
        }
        if (StrUtil.isNotBlank(dto.getShipName())) {
            JSONObject shipInfoJSON = ShipAPIUtil.getShipMMSIByName(dto.getShipName());
            if (!JSONUtil.isNull(shipInfoJSON)) {
                JSONObject data = shipInfoJSON.getJSONArray("data").getJSONObject(0);
                ship.setMmsiCode(data.getStr("mmsi"));
                ship.setShipId(data.getStr("ShipID"));

                //说明用户选择其他类型 需要从船讯网获取船只类型
                if (dto.getShipType().equals("99")) {
                    ship.setShipType(data.getInt("shiptype"));
                }
            }
        }
        ship.setOperatorId(company.getOperateId());
        ship.setUpdateTime(new Date());
        ship.setUpdateBy(currentUserId);
        mapper.updateById(ship);
    }

    @Override
    public void updateBatchCompany(Long[] idList, Long companyId) {
        mapper.updateBatchCompany(idList, companyId);
    }

    @Override
    public ShipVO detail(String id) {
        ShipVO detail = mapper.detail(id);
        detail.setAuthStatusStr(AuthStatusEnum.getInfo(detail.getAuthStatus()));
        detail.setShipTypeStr(ShipTypeEnum.getInfoByCode(Integer.parseInt(detail.getShipType())));
        String shipPic = detail.getShipPic();
        if (StrUtil.isNotBlank(shipPic)) {
            List<String> list = JSONUtil.toList(JSONUtil.parseArray(shipPic), String.class);
            detail.setShipPicList(list);
        }
        return detail;
    }

    @Override
    public List<ShipVO> appList(ShipAppQueryPageDTO dto) {
        String s = (Optional.of(dto)
                .map(ShipAppQueryPageDTO::getShipType)
                .orElse(""));
        if (StrUtil.isNotBlank(s)) {
            dto.setShipTypeList(Arrays.asList(s.split(",")));
        }

        if (null == dto.getDistance()) {
            //如果为空 查询距离设置为最大值
            dto.setDistance(99999.0);
        }

        List<ShipVO> shipAppList = mapper.selectAppList(dto);

        for (ShipVO vo : shipAppList) {
            if (StrUtil.isBlank(vo.getLocation())) {
                vo.setLocation("未知");
            }

            //船舶类型
            vo.setShipTypeText(ShipTypeEnum.getInfo(vo.getShipType()));
            //最后更新时间 时间戳 要转换
            vo.setLastTime(DateUtils.unixToDate(Long.valueOf(vo.getLastTime())));
            //船舶状态
            vo.setNaviStateText(ShipState.getInfo(vo.getNaviState()));
            //航速 毫米/秒转换KM/H
            if (StrUtil.isNotBlank(vo.getSon())) {
                double son = ShipAPIUtil.convertMmPerSecToKnots(Double.parseDouble(vo.getSon()));
                vo.setSon(Double.toString(son));
            } else {
                vo.setSon("0");
            }

            if (StrUtil.isBlank(vo.getDest())) {
                vo.setDest("未知");
            }
        }
        if (ObjUtil.isNotNull(dto.getLat()) && ObjUtil.isNotNull(dto.getLon())) {
            // 计算距离
            return shipAppList.stream()
                    .peek(vo -> {
                        double distance = DistanceCalculatorUtils.calculateDistance(
                                dto.getLat().doubleValue(), dto.getLon().doubleValue(),
                                Double.parseDouble(vo.getLat()), Double.parseDouble(vo.getLon()));
                        vo.setDistance(distance);
                    })
                    .filter(x -> (x.getDistance() - dto.getDistance()) < 0)
                    // 根据距离排序
                    .sorted(Comparator.comparing(ShipVO::getDistance))
                    .collect(Collectors.toList());
        }
        return shipAppList;

    }

    @Override
    public ShipVO appDetailByMmsiCode(String mmsiCode) {
        ShipVO detail = mapper.selectAppByMmsi(mmsiCode);
        //船舶类型
        detail.setShipTypeText(ShipTypeEnum.getInfo(detail.getShipType()));
        //最后更新时间 时间戳 要转换
        detail.setLastTime(DateUtils.unixToDate(Long.valueOf(detail.getLastTime())));
        //船舶状态
        detail.setNaviState(ShipState.getInfo(detail.getNaviState()));
        //航速 毫米/秒转换KM/H
        if (StrUtil.isNotBlank(detail.getSon())) {
            double son = ShipAPIUtil.convertMmPerSecToKnots(Double.parseDouble(detail.getSon()));
            detail.setSon(Double.toString(son));
        }
        //目的地
        if (StrUtil.isBlank(detail.getDest())){
            detail.setDest("未知");
        }
        detail.setAuthStatusStr(AuthStatusEnum.getInfo(detail.getAuthStatus()));
        detail.setShipTypeText(ShipTypeEnum.getInfo(detail.getShipType()));
        String shipPic = detail.getShipPic();
        if (StrUtil.isNotBlank(shipPic)) {
            List<String> list = JSONUtil.toList(JSONUtil.parseArray(shipPic), String.class);
            detail.setShipPicList(list);
        }
        return detail;
    }

    @Override
    public ShipVO appGetByMmsiCode(String mmsiCode) {
        ShipVO vo = mapper.selectAppByMmsi(mmsiCode);
//        ShipVO vo = BeanUtil.copyProperties(this.getByMmsiCode(mmsiCode), ShipVO.class);

        return vo;
    }

    @Override
    public Ship getByMmsiCode(String mmsiCode) {
        return mapper.selectByMmsiCode(mmsiCode);
    }

    @Override
    public List<ShipTrajectoryVO> getAppTrajectoryList(String mmsiCode, String startTime, String endTime) {

        return mapper.selectTrajectory(mmsiCode, startTime, endTime);
    }

    @Override
    public void saveBatchTrajectory(List<ShipTrajectory> allList) {
        mapper.insertBatchTrajectory(allList);
    }

    @Override
    public List<ShipBIBO> biList(String city) {
        return mapper.selectBIList(city);
    }

    @Override
    public List<ShipVO> getShipListByCompanyId(Long companyId) {
        if (Objects.isNull(companyId)) {
            return CollUtil.newArrayList();
        }
        ShipQueryDTO dto = new ShipQueryDTO();
        dto.setCompanyId(companyId.toString());
        dto.setAuthStatus("3");
        List<ShipVO> pageList = mapper.pageList(dto);
        pageList.forEach(ShipServiceImpl::handleVO);
        return pageList;
    }


    @Override
    public List<ShipVO> getUserShipList(String shipName, Integer shipType, String companyId) {
        //说明前端传过来的是查询全部船
        if (StringUtils.isBlank(ShipTypeEnum.getInfoByCode(shipType))) {
            shipType = null;
        }
        //查询驳船的DTO
        List<ShipVO> shipAppUserListDTOList = mapper.getUserShipList(shipName, shipType, companyId);
        //转换为VO
        for (ShipVO x : shipAppUserListDTOList) {
            x.setShipTypeStr(ShipTypeEnum.getInfo(x.getShipType()));
            x.setAuthStatusStr(AuthStatusEnum.getInfo(x.getAuthStatus()));
            //处理照片的pic 转化为List
            String shipPic = x.getShipPic();
            if (StringUtils.isBlank(x.getShipPic())) {
                x.setShipPicList(new ArrayList<>());
            } else {

                List<String> list = JSONUtil.toList(JSONUtil.parseArray(shipPic), String.class);
                x.setShipPicList(list);
                x.setShipPic("");
            }
        }
        return shipAppUserListDTOList;
    }

}
